import {
  Shader,
  ShaderData,
  ShaderProperty,
  ShaderPool,
  ShaderProgram,
  ShaderProgramPool,
  ShaderMacro,
  ShaderMacroCollection,
  ShaderDataGroup,
  ShaderLib
} from "@nirvana/shaders";
import { Vector3, Matrix4, Color } from "@nirvana/math";

import { WebGLCanvas } from "@nirvana/canvas";
import { VertexBufferData, IndexBufferData, DataElement } from "@nirvana/core";
import { parseOBJ } from "./obj.loader";

async function main() {
  const shaderMacroCollection: ShaderMacroCollection = new ShaderMacroCollection();
  console.log(shaderMacroCollection);
  const colorShaderData: ShaderData = new ShaderData(ShaderDataGroup.Material);
  console.log(ShaderDataGroup, colorShaderData);
  const pool: ShaderProgramPool = new ShaderProgramPool();

  // 使用使用 Canvas
  let canvas = document.getElementById("engine-nirvana");
  const webCanvas = new WebGLCanvas(canvas, {
    rate: 1
  });
  const engine = webCanvas.engine;
  const gl = engine.gl;

  const cVS = `
  attribute vec4 a_position;
  attribute vec3 a_normal;

  uniform mat4 u_projection;
  uniform mat4 u_view;
  uniform mat4 u_world;

  uniform mat4 rotateMatrix;
  uniform mat4 scaleMatrix;

  varying vec3 v_normal;

  void main() {
    gl_Position = rotateMatrix * scaleMatrix * a_position;
    v_normal = mat3(rotateMatrix) * a_normal;
  }
  `;
  const cFS = `
  precision mediump float;

  varying vec3 v_normal;

  uniform vec4 u_diffuse;
  uniform vec3 u_lightDirection;

  void main () {
    vec3 normal = normalize(v_normal);
    float fakeLight = dot(u_lightDirection, normal) * .5 + .5;
    gl_FragColor = vec4(u_diffuse.rgb * fakeLight, u_diffuse.a);
  }`;
  const colorDemo = Shader.create("colorDemo", cVS, cFS);
  console.log(colorDemo, Shader.find("colorDemo"));

  const colorProgram: ShaderProgram = colorDemo.getShaderProgram(engine.gl, shaderMacroCollection, pool);
  console.log("color", colorProgram);

  // const response = await fetch("https://webglfundamentals.org/webgl/resources/models/chair/chair.obj");
  const response = await fetch("/dev-static/chair.obj");
  const text = await response.text();
  const obj = parseOBJ(text);
  console.log(obj);

  const parts = obj.geometries.map(({ data }) => {
    // Because data is just named arrays like this
    //
    // {
    //   position: [...],
    //   texcoord: [...],
    //   normal: [...],
    // }
    //
    // and because those names match the attributes in our vertex
    // shader we can pass it directly into `createBufferInfoFromArrays`
    // from the article "less code more fun".

    // create a buffer for each array by calling
    // gl.createBuffer, gl.bindBuffer, gl.bufferData

    const pBuffer = new VertexBufferData(new Float32Array(data.position), [
      new DataElement("a_position", 3, gl.FLOAT, false, 0, 0)
    ]);
    // const tBuffer = new VertexBufferData(
    //   new Float32Array(data.texcoord),
    //   [new DataElement("texcoord", 2, gl.FLOAT, false, 0, 0)]
    // );

    const nBuffer = new VertexBufferData(new Float32Array(data.normal), [
      new DataElement("a_normal", 3, gl.FLOAT, false, 0, 0)
    ]);

    pBuffer.create(gl);
    nBuffer.create(gl);
    return {
      u_diffuse: new Color(Math.random(), Math.random(), Math.random(), 1),
      pBuffer,
      nBuffer
    };
  });

  let w = window.innerWidth;
  let h = window.innerHeight;
  let srate = w / h;

  const _scale = Matrix4.e.scaling(new Vector3(0.1, 0.1 * srate, 0.1));
  const _trans = Matrix4.e.translation(new Vector3(0, -1, 0));
  const rotateMatrix = _scale.clone(); //.leftDot(_trans);
  console.log(_scale, _trans);
  const shaderData: ShaderData = new ShaderData(ShaderDataGroup.Material);
  console.log(ShaderDataGroup, shaderData);
  // { r: 1.0, g: 0.0, b: 0.0, a: 1.0 }

  let r = 0;
  const e = Matrix4.e;
  const axis = new Vector3(0.0, 1.0, 0.0);
  console.log(rotateMatrix);
  engine.update = (gl) => {
    // console.log('--');
    gl.clearColor(0.0, 0.0, 0.0, 1.0);
    // 用上面指定的颜色清除缓冲区
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.enable(gl.DEPTH_TEST);
    // gl.enable(gl.CULL_FACE);
    r += 0.01;
    rotateMatrix.rotationAxisAngle(axis, r);
    // 颜色 start 三
    const u_lightDirection = new Vector3(-1, 3, 5);
    parts.map((part) => {
      colorProgram.bind();

      part.pBuffer.upload(colorProgram._glProgram, gl);
      part.nBuffer.upload(colorProgram._glProgram, gl);
      shaderData.setMatrix("rotateMatrix", rotateMatrix);
      shaderData.setMatrix("scaleMatrix", _scale);
      shaderData.setMatrix("u_projection", e);
      shaderData.setMatrix("u_view", e);
      shaderData.setMatrix("u_world", e);
      shaderData.setVector4("u_diffuse", part.u_diffuse);
      shaderData.setVector3("u_lightDirection", u_lightDirection);
      colorProgram.uploadAll(colorProgram.otherUniformBlock, shaderData);
      part.pBuffer.draw(gl);
    });
    // vBuffer.upload(colorProgram._glProgram, gl);
    // iBuffer.upload(gl);
    // iBuffer.draw(gl);
  };
}

main();
